﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Diagnostics;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;

using DocumentFormat.OpenXml;
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Wordprocessing;
using DocumentFormat.OpenXml.Drawing.Wordprocessing;

namespace BMS.Utilities
{
    public static class WordOpenXMLUtil
    {
        private static String relationshipStr = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/attachedTemplate";

        public static List<SdtElement> RetrievePatternListToRemove(String sourceFile, String letterTypeCode)
        {
            List<SdtElement> removedList = new List<SdtElement>();
            using (WordprocessingDocument oDoc = WordprocessingDocument.Open(sourceFile, true))
            {
                MainDocumentPart p = oDoc.MainDocumentPart;
                String pattern = "^" + letterTypeCode;
                List<SdtElement> temp = p.Document.Descendants<SdtElement>().ToList();
                foreach (SdtElement a in temp)
                {
                    if (Regex.IsMatch(a.SdtProperties.GetFirstChild<Tag>().Val, pattern))
                    {
                        removedList.Add(a);
                    }
                }
            }
            return removedList;
        }

        public static bool RemoveContentControlInDocument(WordprocessingDocument doc, String tagName)
        {
            bool success = false;
            MainDocumentPart p = doc.MainDocumentPart;
            int i = 0;
            while (success == false)
            {
                if (p.Document.Descendants<SdtElement>().ElementAt(i).SdtProperties.GetFirstChild<Tag>().Val == tagName)
                {
                    p.Document.Descendants<SdtElement>().ElementAt(i).Remove();
                    success = true;
                    p.Document.Save();
                    break;
                }
                i++;
            }
            return success;
        }

        public static List<SdtElement> FindTables(WordprocessingDocument doc)
        {
            List<SdtElement> tableElement = new List<SdtElement>();
            MainDocumentPart p = doc.MainDocumentPart;
            String pattern = "Table";
            List<SdtElement> temp = p.Document.Descendants<SdtElement>().ToList();
            foreach (SdtElement a in temp)
            {
                if (Regex.IsMatch(a.SdtProperties.GetFirstChild<Tag>().Val, pattern))
                {
                    tableElement.Add(a);
                }
            }
            return tableElement;
        }

        public static List<SdtElement> RetrieveContentControlList(WordprocessingDocument doc)
        {
            List<SdtElement> element = new List<SdtElement>();
            MainDocumentPart mainP = doc.MainDocumentPart;
            element = mainP.Document.Descendants<SdtElement>().ToList();
            return element;
        }

        public static int CountColumnTable(SdtElement a)
        {
            int numColumns = 0;
            DocumentFormat.OpenXml.Wordprocessing.Table table = a.Descendants<DocumentFormat.OpenXml.Wordprocessing.Table>().Single();
            DocumentFormat.OpenXml.Wordprocessing.TableRow tableRow = table.Elements<DocumentFormat.OpenXml.Wordprocessing.TableRow>().First();
            numColumns = tableRow.Descendants<DocumentFormat.OpenXml.Wordprocessing.TableCell>().Count();
            return numColumns;
        }

        public static void SaveAsDocx(String sourceFilePath, String targetPath, String fileName)
        {
            MemoryStream documentStream;
            using (Stream tplStream = File.OpenRead(sourceFilePath))
            {
                documentStream = new MemoryStream((int)tplStream.Length);
                CopyStream(tplStream, documentStream);
                documentStream.Position = 0L;
            }

            using (WordprocessingDocument oDoc = WordprocessingDocument.Open(documentStream, true))
            {
                oDoc.ChangeDocumentType(DocumentFormat.OpenXml.WordprocessingDocumentType.Document);
                MainDocumentPart mainPart = oDoc.MainDocumentPart;
                mainPart.DocumentSettingsPart.AddExternalRelationship(relationshipStr, new Uri(sourceFilePath, UriKind.Absolute));
                mainPart.Document.Save();
            }
            String fn = targetPath + fileName;
            File.WriteAllBytes(fn, documentStream.ToArray());
        }

        public static void CopyStream(Stream source, Stream target)
        {
            if (source != null)
            {
                MemoryStream mstream = source as MemoryStream;
                if (mstream != null)
                {
                    mstream.WriteTo(target);
                }
                else
                {
                    byte[] buffer = new byte[2048];
                    int length = buffer.Length, size;
                    while ((size = source.Read(buffer, 0, length)) != 0)
                    {
                        target.Write(buffer, 0, size);
                    }
                }
            }
        }

        public static void EndWordTask()
        {
            try
            {
                Process[] pc = Process.GetProcessesByName("WINWORD");
                for (int i = 0; i < pc.Length; i++)
                    pc[i].Kill();
            }
            catch (Exception e)
            {
                Console.WriteLine("Killing Word " + e.Message);
            }
        }

        public static uint GetMaxDocPrId(MainDocumentPart mainPart)
        {
            uint max = 1;

            //Get max id value of docPr elements 
            foreach (DocProperties docPr in mainPart.Document.Descendants<DocProperties>())
            {
                uint id = docPr.Id;
                if (id > max)
                    max = id;
            }
            return max;
        }

        public static SdtElement GetSpecificElement(List<SdtElement> elements, String tagName)
        {
            SdtElement x = null;
            foreach (SdtElement element in elements)
            {
                if (element.SdtProperties.GetFirstChild<Tag>().Val == tagName)
                {
                    x = element;
                    break;
                }
            }
            return x;
        }

        public static void DeleteFiles(String path, String format)
        {
            String filter = format;
            String[] result = Directory.GetFiles(path, filter);
            for (int i = 0; i < result.Length; i++)
            {
                FileInfo fileInfo = new FileInfo(result[i]);
                fileInfo.Delete();
            }
        }

        public static void DeleteFiles(String fileName)
        {
            FileInfo fileInfo = new FileInfo(fileName);
            fileInfo.Delete();
        }

        public static void DeleteFiles(String[] files)
        {
            foreach (String f in files)
            {
                DeleteFiles(f);
            }
        }
    }
}